#ifdef PSOS
namespace std { }

using namespace std;

#include <string.h>
#include <locale>
#endif

#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string.h>
#include "memfs.h"

using namespace std;

//#define DEBUG

#define TAB_WIDTH 4


XMLParser::XMLParser(ostream &newostream)
  /* constructor */
{
  myostream = &newostream;
  myistream = 0;
  indentation = 0;
#ifdef DEBUG
  cerr << "XMLParser::XMLParser : ostream" << endl;
#endif
}
XMLParser::XMLParser(istream &newistream)
  /* constructor */
{
  myostream = 0;
  myistream = &newistream;
  indentation = 0;
#ifdef DEBUG
  cerr << "XMLParser::XMLParser : istream" << endl;
#endif
}

XMLParser::~XMLParser()
{
  /* destructor: nothing to destruct */
}

int XMLParser::StartDir(char *dirname)
{
  for (int i=1; i<indentation * TAB_WIDTH; i++)
    *myostream << " ";
  *myostream << "<" << dirname << ">" << endl;
  indentation += 1;
  return Mfs::MDM_NO_ERROR;
}

int XMLParser::EndDir(char *dirname)
{
  indentation -= 1;
  for (int i=1; i<indentation * TAB_WIDTH; i++)
    *myostream << " ";
  *myostream << "</" << dirname << ">" << endl;
  return Mfs::MDM_NO_ERROR;
}

int XMLParser::AddEntry(char *entryname, char *content)
{
  for (int i=1; i<indentation * TAB_WIDTH; i++)
    *myostream << " ";
  *myostream << "<E " << entryname << " = \"" << content << "\"/>" << endl;
  return Mfs::MDM_NO_ERROR;
}

int XMLParser::ParseSentence(char *sentence, char *content, int *type)
  /* Called by Import. This function returns the content of a token in the
   * sentence
   * type is set to : NONE UNKNOWN STARTDIR ENDDIR ENTRY
   * content is set the the first character of the real start of the token
   * it is concluded with a '\0'
   */
{
  char token[100];
  token[0]='\0';
  *type = TT_NONE;
  //Parse the sentence "[ignore]<[chars]>[ignore]"
  
  //Search the beginning of a token
  unsigned int pos=0;
  while(pos<strlen(sentence))
    if (sentence[pos++]=='<') break;
  if (pos<strlen(sentence))
  {
    //Search the end of a token
    unsigned int endpos=pos;
    while(endpos<strlen(sentence))
      if (sentence[endpos++]=='>') break;
    if (pos<strlen(sentence))
    {
      //Token found
      strncpy(token,&sentence[pos],endpos-pos-1);
      token[endpos-pos-1]='\0';
    }
  }
  if (strlen(token)>0)
  {
#ifdef DEBUG
    cout << "<" << token << ">";
#endif
    if (strncasecmp(token,"E ",2)==0)
    {
      //This is an entry
      *type = TT_ENTRY;
      strcpy(content,&token[2]);
#ifdef DEBUG
      cout << "(entry)" << endl;
#endif
    }
    else
    {
      //This could be a directory, no whitespaces!
      if (token[0]!='/')
      {
	if (strpbrk(token,"\t /\\")==NULL)
	{
	  *type = TT_STARTDIR;
	  strcpy(content,token);
#ifdef DEBUG
	  cout << "(startdir)" << endl;
#endif
	}
	else
	{
	  *type = TT_UNKNOWN;
	  cerr << "<" << token << ">";
	  cerr << "(unknown)" << endl;
	}
      }
      else
      {
	//This could be the end of a dir
	if (strpbrk(&token[1],"\t /\\")==NULL)
	{
	  *type = TT_ENDDIR;
	  strcpy(content,&token[1]);
#ifdef DEBUG
	  cout << "(enddir)" << endl;
#endif
	}
	else
	{
	  *type = TT_UNKNOWN;
	  cerr << "<" << token << ">";
	  cerr << "(unknown)" << endl;
	}
      }
    }
  }
  return 0;
}

int XMLParser::Import(Mshell &msh, const char *l_importpath)
  /*
   * Called by the shell when importing
   * This functions should use the shell to create the internal structure
   */
{
  //Read line by line
  char sentence[1024];
  char newpath[1024];
  char importpath[1024];
  strcpy(importpath, l_importpath);
  if (importpath[strlen(importpath)-1] == '/')
      importpath[strlen(importpath)-1] = '\0';

#ifdef DEBUG
      cerr << "XMLParser: " << importpath << endl;
#endif
  while (myistream->peek()!=-1)
  {
    char token[1024];
    int type;
    myistream->getline(sentence,1023);
    ParseSentence(sentence,token,&type);
    switch (type)
    {
      case TT_STARTDIR:
	strcpy(newpath, importpath);
	      strcat(newpath,"/");
	strcat(newpath,token);
#ifdef DEBUG
	cout <<" Makedir: " << newpath << endl;
#endif
	msh.MkDir(newpath);
	if (int errCode=Import(msh,newpath)) return errCode;
	break;
      case TT_ENDDIR:
#ifdef DEBUG
	cout <<" EndofDir, returning" << endl;
#endif
	return Mfs::MDM_NO_ERROR;
	break;
      case TT_ENTRY:
	//Seperate name from content
	char *name=token; char* endname;
	while ( *(name++)==' ');
	name--;
	endname=strpbrk(&token[1],"\t /\\");
	int equalsfound = false;
	if (endname[0]=='=') equalsfound = true;
	endname[0]='\0';
	strcpy(newpath,importpath);
	strcat(newpath,"/");
	strcat(newpath,name);
	
	//find content
	name=endname;
	while (*(name++)!='\"');
	endname=name;
	while (*(endname++)!='\"');
	endname[-1]='\0';				
#ifdef DEBUG
	cout << "set entry " << newpath << " to \"" << name << "\"" << endl;
#endif
	msh.MkEntry(newpath,name);
	break;
    }
  }
  //End of file
  //TODO: check is this is the first call to import, if so, eof is correct
  return Mfs::MDM_NO_ERROR;
}


#ifdef XMLTEST

int main(int argc, char* argv[])
{
  Mfs myfs;
  Mshell myshell(myfs);
  ofstream myfile("/dev/stdout");
  if (myfile.is_open())
  {
    XMLParser myparser(myfile);
    myparser.StartDir("level1");
    myparser.AddEntry("entry1","boe");
    myparser.StartDir("subdir1");
    myparser.EndDir("subdir1");
    myparser.StartDir("subdir2");
    myparser.EndDir("subdir2");
    myparser.AddEntry("lastoflevel1","true");
    myparser.EndDir("level1");
    myparser.AddEntry("onebutlastentry","false");
  }
  return 0;
}
#endif













































